#include "lwin.h"
#include "lcoinwidget.h"
#include <QtDebug>

LWin::LWin(QWidget *parent, Qt::WFlags f)
    : QMainWindow(parent, f) {
    
    /* SET UP MAIN FORM DATA */
    setWindowTitle("MUDlooter"); 
    setMinimumHeight(200);
    setMinimumWidth(400);
    qApp->setWindowIcon(QIcon(":/ico"));
    createActions();

    /* SETUP WIDGETS */
    central = new QFrame(this);
    QVBoxLayout *layout = new QVBoxLayout(central);
    layout->setMargin(2);
    layout->setSpacing(2);
    setCentralWidget(central);

    log = new QListWidget(central);
    log->setSelectionMode(QAbstractItemView::ContiguousSelection);
    layout->addWidget(log);

    coin = new QFrame(central);
    QHBoxLayout *coinLayout = new QHBoxLayout(coin);

    orb = new LCoinWidget(this, 0, LCoinWidget::Orb);
    coinLayout->addWidget(orb);
    crown = new LCoinWidget(this, 0, LCoinWidget::Crown);
    coinLayout->addWidget(crown);
    danar = new LCoinWidget(this, 0, LCoinWidget::Danar);
    coinLayout->addWidget(danar);
    slag = new LCoinWidget(this, 0, LCoinWidget::Slag);
    coinLayout->addWidget(slag);

    coinLayout->setMargin(1);
    coinLayout->setSpacing(2);

    layout->addWidget(coin);
    
    QFrame *totalBar = new QFrame(central);
    QHBoxLayout *totalLayout = new QHBoxLayout(totalBar);
    //totalLayout->addWidget(new QSpacerItem(10, 10));
    QToolButton *toolClear = new QToolButton(totalBar);
    toolClear->setDefaultAction(actClear);
    totalLayout->addWidget(toolClear);
    totalLayout->addWidget(new QLabel("Total: ", totalBar));
    edTotal = new QLineEdit(totalBar);
    edTotal->setReadOnly(true);
    edTotal->setFocusPolicy(Qt::NoFocus);
    edTotal->setMaximumWidth(75);
    edTotal->setMinimumWidth(75);
    totalLayout->addWidget(edTotal);
    totalLayout->addWidget(new QLabel("slags", totalBar));
    QToolButton *toolSplit = new QToolButton(totalBar);
    toolSplit->setDefaultAction(actSplit);
    totalLayout->addWidget(toolSplit);

    totalLayout->setMargin(1);
    totalLayout->setSpacing(3);


    layout->addWidget(totalBar);
    layout->setAlignment(totalBar, Qt::AlignRight);

    m_icon = new QSystemTrayIcon(QIcon(":/ico"), this);        

    /* SETUP INTERFACES */
    createToolbars(); 
    setupMenu();
    
    /* SETUP TIMERS */
    m_flash_timer = new QTimer(this);
    m_update_timer = new QTimer(this);
    
    /* SETUP CONNECTIONS */
    connect(orb, SIGNAL(valueChanged()), this, SLOT(updateTotal()));
    connect(crown, SIGNAL(valueChanged()), this, SLOT(updateTotal()));
    connect(danar, SIGNAL(valueChanged()), this, SLOT(updateTotal()));
    connect(slag, SIGNAL(valueChanged()), this, SLOT(updateTotal()));
    connect(m_icon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 
            this, SLOT(iconClicked(QSystemTrayIcon::ActivationReason)));   
    connect(m_flash_timer, SIGNAL(timeout()), this, SLOT(flashIcon()));   
    connect(m_update_timer, SIGNAL(timeout()), this, SLOT(periodicUpdates()));
    connect(actTop, SIGNAL(toggled(bool)), this, SLOT(toggleAlwaysOnTop(bool)));
    connect(actMute, SIGNAL(toggled(bool)), this, SLOT(toggleAudio(bool)));
    connect(actInsert, SIGNAL(triggered()), this, SLOT(pasteLoot()));
    connect(actInsert2, SIGNAL(triggered()), this, SLOT(pasteLoot()));
    connect(actCopy, SIGNAL(triggered()), this, SLOT(copyData()));
    connect(actSelectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
    connect(actUndo, SIGNAL(triggered()), this, SLOT(historyBack()));
    connect(actRedo, SIGNAL(triggered()), this, SLOT(historyForward()));
    connect(actClear, SIGNAL(triggered()), this, SLOT(historyClear()));
    connect(actSplit, SIGNAL(triggered()), this, SLOT(figureSplit()));
    connect(actClose, SIGNAL(triggered()), this, SLOT(close()));
    connect(actSetVisible, SIGNAL(triggered()), this, SLOT(toggleVisible()));
    connect(actPaste, SIGNAL(triggered()), this, SLOT(pasteLoot()));    

    /* SETUP INITIAL DATA */
    m_showing = true;
    m_flash_cnt = 0;
    m_flash_on = false;
    m_audio = true;
    updateTotal();
    historyClear();
    log->addAction(actSelectAll);
    log->addAction(actInsert2);
    m_icon->show();

    /* SETUP SETTINGS */
    readSettings();
    move(m_pos);
    resize(m_size);

}

void LWin::periodicUpdates() {
    if(!m_icon->isVisible()) {    
        popUpMessage();
    }
}

void LWin::changeEvent(QEvent *e) {
    if(e->type() == QEvent::WindowStateChange) {
        if(isMinimized()) { toggleVisible(); } 
    } else { e->accept(); QMainWindow::changeEvent(e); }
}
#ifdef Q_OS_WIN32
bool LWin::winEvent( MSG *m, long *result ) {    
    switch (m->message) {
        case WM_SIZE:
            if (m->wParam == SIZE_MINIMIZED) {
                ShowWindow(winId(), SW_HIDE);
                return true;
            } break;
        default: break;
    }    
    return QWidget::winEvent(m, result);
} 
#endif
void LWin::copyData() {
    QClipboard *clip = QApplication::clipboard();
    QString data;
    QList<QListWidgetItem*> items = log->selectedItems();
    
    if(items.count()) {
        QListIterator<QListWidgetItem*> i(items);
        while(i.hasNext()) {
            QListWidgetItem *w = i.next();
            data = QString("%1\n%2").arg(data).arg(w->text());
        }
    }
    if(!data.isNull()) clip->setText(data);    
}

void LWin::createActions() {
    actTop = new QAction(QIcon(":/top"), "Always on top", this);
    actTop->setCheckable(true);

    actMute = new QAction(QIcon(":/mute"), "Mute audio", this);
    actMute->setCheckable(true);
    actMute->setVisible(QSound::isAvailable());

    actInsert = new QAction(QIcon(":/add"), "Insert new loot spam (Insert)",
        this);
    actInsert->setShortcut(tr("Insert"));

    actInsert2 = new QAction(QIcon(":/add"), "Insert new loot spam (Ctrl-V)",
        this);
    actInsert2->setShortcut(tr("Ctrl+V"));

    actCopy = new QAction(QIcon(":/copy"), "&Copy (Ctrl-C)", this);
    actCopy->setShortcut(tr("Ctrl+C"));

    actSelectAll = new QAction("&Select All", this);
    actSelectAll->setShortcut(tr("Ctrl+A"));

    actUndo = new QAction(QIcon(":/undo"), "Undo (Ctrl-Z)", this);
    actUndo->setShortcut(tr("Ctrl+Z"));

    actRedo = new QAction(QIcon(":/redo"), "Redo (Ctrl-Shift-Z)", this);
    actRedo->setShortcut(tr("Shift+Ctrl+Z"));

    actClear = new QAction(QIcon(":/clear"), "Clear", this);

    actSplit = new QAction(QIcon(":/split"), "Split Loot", this);

    actClose = new QAction(tr("E&xit"), this);

    actSetVisible = new QAction(tr("&Hide"), this);

    actPaste = new QAction(tr("&Paste"), this);
    actPaste->setIcon(QIcon(":/add"));
}

void LWin::selectAll() {
    for(int i = 0; i < log->count(); i++) {
        log->setItemSelected(log->item(i), true);
    }
}

void LWin::iconClicked(QSystemTrayIcon::ActivationReason reason) {
    switch(reason) {
        case QSystemTrayIcon::Unknown: 
        case QSystemTrayIcon::Context: break;
        case QSystemTrayIcon::Trigger: 
        case QSystemTrayIcon::DoubleClick: toggleVisible(); break;
        case QSystemTrayIcon::MiddleClick: pasteLoot(); break;
    }
}

void LWin::setupMenu() {
    menu = new QMenu("MUDlooter", this);
    menu->addAction(actSetVisible);
    menu->addAction(actPaste);
    menu->addSeparator();
    menu->addAction(actClose);
    m_icon->setContextMenu(menu);
}

void LWin::toggleVisible() {
    m_showing = !isVisible();
    //m_showing = !m_showing;

    setVisible(m_showing);
    if(m_showing) showNormal();

    actSetVisible->setText(m_showing ? tr("&Hide") : tr("&Show"));

    if(!m_showing) {
            QTimer::singleShot(1000, this, SLOT(periodicUpdates()));
            m_update_timer->start(1 * 60 * 1000);
    }
}

void LWin::flashIcon() {
    if(isVisible()) { m_flash_timer->stop(); return ; }
    m_flash_cnt++;
    if(m_flash_cnt>7) m_flash_cnt = 0;
    m_flash_on = !m_flash_on;

    if(m_flash_on) m_icon->setIcon(QIcon(":/ico2"));
    else m_icon->setIcon(QIcon(":/ico"));

    if(!m_flash_cnt) m_flash_timer->stop();
}

void LWin::createToolbars() {
    tbMain = addToolBar(tr("Main"));
    tbMain->addAction(actTop);
    tbMain->addAction(actMute);
    tbMain->addSeparator();
    tbMain->addAction(actInsert);
    tbMain->addAction(actCopy);
    tbMain->addAction(actUndo);
    tbMain->addAction(actRedo);
    /*
    tbMain->addSeparator();

    tbMain->addAction(actClear);
    tbMain->addWidget(new QLabel("Total: "));
    edTotal = new QLineEdit(this);

    edTotal->setReadOnly(true);
    edTotal->setFocusPolicy(Qt::NoFocus);
    tbMain->addWidget(edTotal);
    tbMain->addWidget(new QLabel("slags"));
    tbMain->addAction(actSplit);
    */
    tbMain->setIconSize(QSize(22, 22));
    tbMain->setMovable(false);
}

void LWin::popUpMessage() {
    QString mess;

    if(!isVisible()) {
        mess = tr("Total Loot: %1")
               .arg(m_total);
        m_icon->showMessage("MUDlooter", mess, QSystemTrayIcon::Information, 
            30*1000);
    }
    m_icon->setToolTip(tr("Total Loot: %1").arg(m_total));
}

void LWin::pasteLoot() {
    QClipboard *clip = QApplication::clipboard();
    char cointype[80];
    char throwaway[80];
    int num, c_type;
    bool shop;
    QString shop_object;
    char fullstop;

    c_type = 0;

    QStringList lines = clip->text().split("\n");
    for(int i = 0; i < lines.count(); i++) {
        shop = false;
        QString line = lines[i];
        if(line.startsWith(">")) {
            line = line.remove(0,1);
        }
        line = line.trimmed();
        if(line.startsWith("You sell") && line.contains(" for ")) {
            QString tmp = line;
            QStringList parts = tmp.split(" for ");
            parts[1] = parts[1].mid(0, parts[1].length()-1);
            parts[0] = parts[0].mid(8, parts[0].length()-8);
            line = QString("[SHOP] %1").arg(parts[1].trimmed());
            shop_object = parts[0];
            shop=true;
        }
        if(line.isEmpty()) continue;
        const char* text = line.toLatin1();

        if(
            sscanf(text, "[SHOP] %d %s", &num, cointype) == 2 ||
            sscanf(text, "You get %d %s coins%c",
                &num, cointype, &fullstop) == 3 ||
            sscanf(text, "You get %d %s coin%c",
                &num, cointype, &fullstop) == 3 ||
            sscanf(text, "[LOOT] Obtained: %d %s %s",
                &num, throwaway, cointype) == 3 ||
            sscanf(text, "[LOOT]           %d %s %s",
                &num, throwaway, cointype) == 3 ||
            sscanf(text, "[LOOT]           (%s %s %d %s %s",
                    throwaway, throwaway, &num, throwaway, cointype) == 5 ||
            sscanf(text, "[LOOT] Obtained:  (%s %s %d %s %s",
                throwaway, throwaway, &num, throwaway, cointype) == 5
        ) {
            if(shop) {
                line = QString("[SHOP] %1").arg(shop_object.trimmed());
            }

            addCoin(resolveCoinType(cointype), num);

            logText(QString("%1 => %2 %3").arg(line).arg(num).arg(cointype));
            if(m_audio) QSound::play("paste.wav");
            actUndo->setEnabled(true);
            actClear->setEnabled(true);
            if(m_trash.size()) {
                m_trash.clear();
                actRedo->setEnabled(false);
            }
        }
    }
}

LWin::CoinType LWin::resolveCoinType(const QString c_type) {
    if(c_type == "danar") return LWin::Danar;
    if(c_type == "crown") return LWin::Crown;
    if(c_type == "orb") return LWin::Orb;
    return LWin::Slag;
}

void LWin::addCoin(const LWin::CoinType c_type, const int num) {
    switch(c_type) {
        case LWin::Slag: slag->add(num); break;
        case LWin::Danar: danar->add(num); break;
        case LWin::Crown: crown->add(num); break;
        case LWin::Orb: orb->add(num); break;
    }
    addHistory(c_type, num); 
}  

void LWin::figureSplit() {
    bool ok;
    int i = QInputDialog::getInteger(this, tr("Split Loot"),
        tr("How many people are you splitting with?"), 2, 2, 10, 1, &ok);
    int o = orb->value() / i;
    int c = crown->value() / i;
    int d = danar->value() / i;
    int s = slag->value() / i;

    QString msg = "";
    if(o) msg += QString("==> Orb: %1\n").arg(o);
    if(c) msg += QString("==> Crown: %1\n").arg(c);
    if(d) msg += QString("==> Danar: %1\n").arg(d);
    if(s) msg += QString("==> Slag: %1\n").arg(s);

    if(!msg.length()) msg = "There is not enough coin to split between that "
        "many people.";
    if(ok) {
        orb->add(i * o * -1);
        crown->add(i * c * -1);
        danar->add(i * d * -1);
        slag->add(i * s * -1);
    
        QString lootmsg = QString("%1\n%2").arg("SPLIT COIN").arg(msg);
        logText(lootmsg, Qt::darkGreen);
        if(orb->value() || crown->value() || danar->value() || slag->value())
            logText("There is coin remaining.\n", Qt::darkMagenta);
    }
}

void LWin::updateTotal() {
    edTotal->setText(QString::number(orb->slagValue() +
        crown->slagValue() + danar->slagValue() + slag->slagValue()));
    if(!actSplit->isEnabled()) actSplit->setEnabled(true);
    if(!actClear->isEnabled()) actClear->setEnabled(true);
    m_total = edTotal->text().toInt();
    popUpMessage();
    if(!m_flash_timer->isActive()) m_flash_timer->start(500);
}

void LWin::logText(QString str, Qt::GlobalColor color) {
    QListWidgetItem *lw = new QListWidgetItem();
#ifdef Q_OS_WIN32
    lw->setFont(QFont("Bitstream Vera Sans Mono,10"));
#endif
    lw->setTextColor(QColor(color));
    lw->setText(str);
    log->addItem(lw);
    log->scrollToItem(log->item(log->count()-1));
    if(!m_history.size()) actUndo->setEnabled(false);

    if(log->count() > 700) 
        for(int x = 501; x < log->count(); x++) 
            log->takeItem(x);
    log->scrollToItem(log->item(log->count()-1));
}

void LWin::toggleAlwaysOnTop(bool v){
    QPoint p = pos();
    QSize s = size();
    if(v){
        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
    } else {
        setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
    }
    move(p);
    resize(s);
    show();
}

void LWin::toggleCompactMode(bool v) {
    coin->setVisible(v);
    log->setVisible(v);
    setMaximumHeight(0);
}

void LWin::toggleAudio(bool v) {
    m_audio = !v;
}

void LWin::historyBack() {
    history h = m_history.takeLast();
    QString c_type;
    switch (h.h_type) {
        case LWin::Orb:
            c_type = "orb";
            if(orb->value() - h.h_value < 0) {
                QMessageBox::critical(this, "MUDlooter", QString("The results "
                    "of undo must not be less than zero %1.").arg(c_type));
                return ;
            }
            orb->add(-h.h_value);
            break;
        case LWin::Crown:
            c_type = "crown";
            if(crown->value() - h.h_value < 0) {
                QMessageBox::critical(this,
                "MUDlooter",
                QString("The results of undo must not be less than zero %1.")
                .arg(c_type));
                return ;
            }
            crown->add(-h.h_value);
            break;
        case LWin::Danar:
            c_type = "danar";
            if(danar->value() - h.h_value < 0) {
                QMessageBox::critical(this,
                "MUDlooter",
                QString("The results of undo must not be less than zero %1.")
                .arg(c_type));
                return ;
            }
            danar->add(-h.h_value);
            break;
        case LWin::Slag:
            c_type = "slag";
            if(slag->value() - h.h_value < 0) {
                QMessageBox::critical(this,
                "MUDlooter",
                QString("The results of undo must not be less than zero %1.")
                .arg(c_type));
                return ;
            }
            slag->add(-h.h_value);
            break;
    }
    actRedo->setEnabled(true);
    logText(QString("[UNDO] %1 %2").arg(h.h_value).arg(c_type), Qt::red);
        if(!m_history.size()) actUndo->setEnabled(false);
    m_trash += h;

}

void LWin::historyForward() {
    history h = m_trash.takeLast();
    QString c_type;
    switch (h.h_type) {
        case LWin::Orb:
            orb->add(h.h_value);
            c_type = "Orb";
            break;
        case LWin::Crown:
            crown->add(h.h_value);
            c_type = "Crown";
            break;
        case LWin::Danar:
            danar->add(h.h_value);
            c_type = "Danar";
            break;
        case LWin::Slag:
            slag->add(h.h_value);
            c_type = "Slag";
            break;
    }
    actUndo->setEnabled(true);
    logText(QString("[REDO] %1 %2").arg(h.h_value).arg(c_type), Qt::blue);
    if(!m_trash.size()) actRedo->setEnabled(false);
    m_history += h;
}

void LWin::historyClear() {
    actRedo->setEnabled(false);
    actUndo->setEnabled(false);
    m_history.clear();
    log->clear();
    orb->setValue(0);
    crown->setValue(0);
    danar->setValue(0);
    slag->setValue(0);
    updateTotal();
    actSplit->setEnabled(false);
    actClear->setEnabled(false);
    m_undo = 0;
}

void LWin::addHistory(int h_type, int h_value) {
    history h;
    h.h_type = h_type;
    h.h_value = h_value;
    m_history.append(h);
}

void LWin::writeSettings() {
    QSettings m_settings("Ellenia Group", "MUDlooter");
    m_settings.setValue("pos", pos());
    m_settings.setValue("size", size());
}

void LWin::readSettings() {
    QSettings m_settings("Ellenia Group", "MUDlooter");
    m_pos = m_settings.value("pos", QPoint(200, 200)).toPoint();
    m_size = m_settings.value("size", QSize(400, 400)).toSize();
}

void LWin::closeEvent(QCloseEvent *event) {
    writeSettings();
    delete(m_icon);
    QMainWindow::closeEvent(event);
}
